using System;
using System.Diagnostics;
using System.ComponentModel;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
using System.IO;
using System.Xml.Serialization;

namespace Waymex.Interop
{
    /// <summary>
    /// This class contains managed versions of the native methods exposed in Waymex.Interop.NativeMethods.
    /// It includes helper functions error handling and marshalling specifics.
    /// TODO: Enhance all these methods to handle overlapped results and accept standard CLR Types.
    /// </summary>
    internal sealed class ManagedMethods
    {
        //private constructor
        private ManagedMethods() { }

        internal static void CancelIo(IntPtr hFile)
        {
            if (!Waymex.Interop.NativeMethods.CancelIo(hFile))
            {
                Int32 err = Marshal.GetLastWin32Error();
                throw new Win32Exception(err);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        internal static byte[] ReadDeviceIoControlOverlapped(
           IntPtr hDevice,
           uint numberOfBytesToRead,
           IntPtr overlappedEvent,
           UInt32 dwIoControlCode,
           int timeoutSeconds)
        {
            IntPtr lpOutBuffer = Marshal.AllocHGlobal((int)numberOfBytesToRead);
            return ReadDeviceIoControlOverlapped(hDevice, lpOutBuffer, numberOfBytesToRead, overlappedEvent, dwIoControlCode, timeoutSeconds);

        }
        internal static byte[] ReadDeviceIoControlOverlapped(
            IntPtr hDevice,
            IntPtr lpOutBuffer,
            uint numberOfBytesToRead,
            IntPtr overlappedEvent,
            UInt32 dwIoControlCode,
            int timeoutSeconds)
        {
            //declarations
            bool success = false;
            bool complete = false;
            byte[] dataReturned = new byte[numberOfBytesToRead];
            byte[] data = null;
            double timer = 0;
            uint lpBytesReturned = 0;
            int err = 0;
            //IntPtr lpOutBuffer = IntPtr.Zero;

            //uint lpNumberOfBytesTransferred = 0;
            NativeMethods.OVERLAPPED lpOverlapped = new NativeMethods.OVERLAPPED();
            //NativeMethods.DEVICEIODATA lpOutBuffer = new NativeMethods.DEVICEIODATA();

            lpOverlapped.hEvent = overlappedEvent;

            try
            {

                success = NativeMethods.DeviceIoControl(hDevice,
                    dwIoControlCode,
                    IntPtr.Zero,
                    0,
                    lpOutBuffer,
                    numberOfBytesToRead,
                    ref lpBytesReturned,
                    ref lpOverlapped);

                if (!success)
                    err = Marshal.GetLastWin32Error();
                else
                    err = NativeMethods.NO_ERROR;

                if (!success)
                {
                    switch (err)
                    {
                        case NativeMethods.ERROR_HANDLE_EOF:
                            {
                                // we have read all there is to read
                                success = true;
                                break;
                            }

                        case NativeMethods.ERROR_IO_PENDING:
                            {

                                timer = Timer();

                                while (!complete)
                                {
                                    //required for .net2 on XP
                                    System.Windows.Forms.Application.DoEvents();

                                    complete = NativeMethods.GetOverlappedResult(hDevice, ref lpOverlapped, ref lpBytesReturned, false);
                                    if (!complete)
                                        err = Marshal.GetLastWin32Error();
                                    else
                                        err = NativeMethods.NO_ERROR;

                                    if (complete)
                                    {
                                        Marshal.Copy(lpOutBuffer, dataReturned, 0, dataReturned.Length);
                                        success = true;
                                        break;
                                    }
                                    else
                                    {
                                        switch (err)
                                        {
                                            case NativeMethods.ERROR_HANDLE_EOF:
                                                {
                                                    complete = true;
                                                    success = true;
                                                    break;
                                                }
                                            default:
                                                {
                                                    success = false;
                                                    break;
                                                }
                                        }
                                    }


                                    //see if we have timed out
                                    if (Timer() > timer + timeoutSeconds)
                                    {
                                        lpBytesReturned = 0;
                                        break;
                                    }
                                }
                                break;
                            }
                    }
                }
                else
                {
                    //was successful at first attempt
                    Marshal.Copy(lpOutBuffer, dataReturned, 0, dataReturned.Length);
                }

                //tidy up data
                if (success && lpBytesReturned > 0)
                {
                    //create an array the correct size for this packet
                    data = new byte[lpBytesReturned];
                    Array.Copy(dataReturned, 0, data, 0, lpBytesReturned);
                }
            }
            catch (Exception e)
            {
                throw (e);
            }
            finally
            {
                //free up memory
                //Marshal.FreeHGlobal(lpOutBuffer);
                //NativeMethods.ResetEvent(overlappedEvent);
            }

            return data;
        }
        internal static bool WriteFileOverlapped(IntPtr hFile, IntPtr overlappedEvent, byte[] buffer, int timeoutSeconds)
        {
            bool success = false;
            uint lpNumberOfBytesWritten = 0;
            uint nNumberOfBytesToWrite = 0;
            NativeMethods.OVERLAPPED lpOverlapped = new NativeMethods.OVERLAPPED();
            int intError = 0;
            double dblTimer = 0;
            //IntPtr ptrUWO = IntPtr.Zero;

            nNumberOfBytesToWrite = (uint)buffer.Length;
            lpOverlapped.hEvent = overlappedEvent;

            IntPtr lpBuffer = Marshal.AllocHGlobal(buffer.Length);
            Marshal.Copy(buffer, 0, lpBuffer, buffer.Length);

            success = NativeMethods.WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, ref lpNumberOfBytesWritten, ref lpOverlapped);

            //need to determine if the overlapped write has completed
            dblTimer = Timer();
            while (nNumberOfBytesToWrite > lpNumberOfBytesWritten)
            {
                //required for XP systems
                System.Windows.Forms.Application.DoEvents();

                success = NativeMethods.GetOverlappedResult(hFile, ref lpOverlapped, ref lpNumberOfBytesWritten, false);

                //see if we have timed out
                if (Timer() > dblTimer + timeoutSeconds)
                {
                    break;
                }
            }

            NativeMethods.ResetEvent(overlappedEvent);

            if (success)
            {
                return true;
            }

            else
            {

                intError = Marshal.GetLastWin32Error();
                return false;

            }
        }
        /// <summary>
        /// Method that performs a full overlapped read until the number of bytes
        /// specified is read or until the timeout period expires.
        /// </summary>
        /// <returns></returns>
        internal static byte[] ReadFileOverlapped(IntPtr hFile,
            uint numberOfBytesToRead,
            IntPtr overlappedEvent,
            int timeoutSeconds)
        {
            //marshal a pointer to the data buffer
            IntPtr lpBuffer = Marshal.AllocHGlobal((int)numberOfBytesToRead);
            return ReadFileOverlapped(hFile, lpBuffer, numberOfBytesToRead, overlappedEvent, timeoutSeconds);

        }
        /// Method that performs a full overlapped read until the number of bytes
        /// specified is read or until the timeout period expires. This overload accepts an
        /// externally created buffer allowing for greater control.
        internal static byte[] ReadFileOverlapped(IntPtr hFile,
            IntPtr lpBuffer,
            uint numberOfBytesToRead,
            IntPtr overlappedEvent,
            int timeoutSeconds)
        {

            //declarations
            bool success = false;
            bool complete = false;
            Double timer = 0;
            Int32 err = 0;
            byte[] data = null;
            uint lpNumberOfBytesRead = 0;
            byte[] dataReturned = new byte[numberOfBytesToRead];
            NativeMethods.OVERLAPPED lpOverlapped = new NativeMethods.OVERLAPPED();
            uint lpNumberOfBytesTransferred = 0;

            /*
             * ReadFile returns false with error ERROR_IO_PENDING when more data is avalable
             * Event set to signalled state whenread completes.
             * If Readfile gets to end of file then it returns false and error is ERROR_HANDLE_EOF.
             * If subsequent GetOverlapped Result gets to end of file then this also returns false
             * and error is ERROR_HANDLE_EOF.
             * 
             */

            lpOverlapped.hEvent = overlappedEvent;

            try
            {
                //marshal a pointer to the data buffer
                //lpBuffer = Marshal.AllocHGlobal((int)numberOfBytesToRead);

                //call native function
                success = Waymex.Interop.NativeMethods.ReadFile(hFile,
                    lpBuffer,
                    numberOfBytesToRead,
                    ref lpNumberOfBytesRead,
                    ref lpOverlapped);

                if (!success)
                    err = Marshal.GetLastWin32Error();
                else
                    err = NativeMethods.NO_ERROR;

                if (!success)
                {
                    switch (err)
                    {
                        case NativeMethods.ERROR_HANDLE_EOF:
                            {
                                // we have read all there is to read
                                success = true;
                                break;
                            }

                        case NativeMethods.ERROR_IO_PENDING:
                            {
                                //asynchronous i/o is still in progress
                                timer = Timer();

                                //loop until it is complete
                                while (!complete)
                                {
                                    //required for .net2 on XP
                                    System.Windows.Forms.Application.DoEvents();

                                    //get the overlapped result
                                    complete = NativeMethods.GetOverlappedResult(hFile, ref lpOverlapped, ref lpNumberOfBytesTransferred, false);
                                    if (!complete)
                                        err = Marshal.GetLastWin32Error();
                                    else
                                        err = NativeMethods.NO_ERROR;

                                    if (complete)
                                    {
                                        Marshal.Copy(lpBuffer, dataReturned, 0, dataReturned.Length);
                                        success = true;
                                        break;
                                    }
                                    else
                                    {
                                        switch (err)
                                        {
                                            case NativeMethods.ERROR_HANDLE_EOF:
                                                {
                                                    complete = true;
                                                    success = true;
                                                    break;
                                                }
                                            default:
                                                {
                                                    success = false;
                                                    break;
                                                }
                                        }
                                    }

                                    //see if we have timed out
                                    if (Timer() > (timer + timeoutSeconds))
                                    {
                                        lpNumberOfBytesTransferred = 0;
                                        success = false;
                                        break;
                                    }

                                }
                                break;
                            }
                        default:
                            {
                                break;
                            }
                    }
                }
                else
                {
                    //was successful at first attempt
                    Marshal.Copy(lpBuffer, dataReturned, 0, dataReturned.Length);
                }

                //tidy up data
                if (success && lpNumberOfBytesTransferred > 0)
                {

                    //make an array exactly the correct length
                    data = new byte[lpNumberOfBytesTransferred];

                    //copy the returned data in to the new array
                    Array.Copy(dataReturned, data, lpNumberOfBytesTransferred);
                }
            }
            catch (Exception e)
            {
                throw (e);
            }
            finally
            {
                //free up memory
                //Marshal.FreeHGlobal(lpBuffer);
                //NativeMethods.ResetEvent(overlappedEvent);
            }

            return data;
        }
        private static double Timer()
        {
            DateTime dtTimer;

            dtTimer = DateTime.Now;

            //Debug.Write("Timer() ");     
            //Debug.WriteLine(dtTimer.Ticks % 711573504 / 1e+007);
            return (double)dtTimer.Ticks % 711573504 / 1e+007;
        }
        internal static void ReadFile(IntPtr hFile,
            IntPtr lpBuffer,
            UInt32 nNumberOfBytesToRead,
            ref UInt32 lpNumberOfBytesRead,
            ref Waymex.Interop.NativeMethods.OVERLAPPED lpOverlapped)
        {
            if (!Waymex.Interop.NativeMethods.ReadFile(hFile,
                lpBuffer,
                nNumberOfBytesToRead,
                ref lpNumberOfBytesRead,
                ref lpOverlapped))
            {
                Int32 err = Marshal.GetLastWin32Error();
                throw new Win32Exception(err);
            }
        }
        internal static void WriteFile(IntPtr hFile,
            IntPtr lpBuffer,
            UInt32 nNumberOfBytesToWrite,
            ref UInt32 lpNumberOfBytesWritten,
            ref Waymex.Interop.NativeMethods.OVERLAPPED lpOverlapped)
        {
            if (!Waymex.Interop.NativeMethods.WriteFile(hFile,
                lpBuffer,
                nNumberOfBytesToWrite,
                ref lpNumberOfBytesWritten,
                ref lpOverlapped))
            {
                Int32 err = Marshal.GetLastWin32Error();
                throw new Win32Exception(err);
            }
        }
        internal static IntPtr CreateEvent(
            IntPtr lpEventAttributes,
            int bManualReset,
            int bInitialState,
            string lpName)
        {
            IntPtr handle = Waymex.Interop.NativeMethods.CreateEvent(lpEventAttributes,
                bManualReset,
                bInitialState,
                lpName);
            if (handle == IntPtr.Zero)
            {
                Int32 err = Marshal.GetLastWin32Error();
                throw new Win32Exception(err);
            }

            return handle;
        }

        internal static IntPtr CreateFile(
            String lpFileName,
            UInt32 dwDesiredAccess,
            UInt32 dwShareMode,
            IntPtr lpSecurityAttributes,
            UInt32 dwCreationDisposition,
            UInt32 dwFlagsAndAttributes,
            IntPtr hTemplateFile)
        {
            IntPtr handle = Waymex.Interop.NativeMethods.CreateFile(lpFileName,
                dwDesiredAccess,
                dwShareMode,
                lpSecurityAttributes,
                dwCreationDisposition,
                dwFlagsAndAttributes,
                hTemplateFile
                );

            if (handle == IntPtr.Zero)
            {
                Int32 err = Marshal.GetLastWin32Error();
                throw new Win32Exception(err);
            }

            return handle;
        }

        internal static void SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet)
        {
            if (!Waymex.Interop.NativeMethods.SetupDiDestroyDeviceInfoList(DeviceInfoSet))
            {
                Int32 err = Marshal.GetLastWin32Error();
                throw new Win32Exception(err);
            }
        }

        internal static void SetupDiGetDeviceInterfaceDetail(
            IntPtr DeviceInfoSet,
            ref Waymex.Interop.NativeMethods.DEVICE_INTERFACE_DATA DeviceInterfaceData,
            //ref Waymex.Interop.NativeMethods.DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData,
            IntPtr DeviceInterfaceDetailData,
            int DeviceInterfaceDetailDataSize,
            ref int RequiredSize,
            IntPtr DeviceInfoData)
        {
            if (!Waymex.Interop.NativeMethods.SetupDiGetDeviceInterfaceDetail(DeviceInfoSet,
                ref DeviceInterfaceData,
                DeviceInterfaceDetailData,
                DeviceInterfaceDetailDataSize,
                ref RequiredSize,
                DeviceInfoData))
            {
                Int32 err = Marshal.GetLastWin32Error();
                throw new Win32Exception(err);
            }
        }

        internal static IntPtr SetupDiGetClassDevs(
            ref Guid ClassGuid,
            string Enumerator,
            IntPtr hwndParent,
            uint Flags)
        {
            IntPtr handle = Waymex.Interop.NativeMethods.SetupDiGetClassDevs(ref ClassGuid,
                Enumerator,
                hwndParent,
                Flags);
            if (handle == IntPtr.Zero)
            {
                Int32 err = Marshal.GetLastWin32Error();
                throw new Win32Exception(err);
            }

            return handle;

        }

        internal static void CloseHandle(IntPtr hObject)
        {
            if (!Waymex.Interop.NativeMethods.CloseHandle(hObject))
            {
                Int32 err = Marshal.GetLastWin32Error();
                throw new Win32Exception(err);
            }
        }

        internal static void SetupDiEnumDeviceInterfaces(
            IntPtr DeviceInfoSet,
            IntPtr DeviceInfoData,
            ref Guid InterfaceClassGuid,
            int MemberIndex,
            ref Waymex.Interop.NativeMethods.DEVICE_INTERFACE_DATA DeviceInterfaceData)
        {
            if (!Waymex.Interop.NativeMethods.SetupDiEnumDeviceInterfaces(DeviceInfoSet,
                DeviceInfoData,
                ref InterfaceClassGuid,
                MemberIndex,
                ref DeviceInterfaceData))
            {
                Int32 err = Marshal.GetLastWin32Error();
                throw new Win32Exception(err);
            }
        }

        internal static void ResetEvent(
            IntPtr hEvent)
        {
            if (!Waymex.Interop.NativeMethods.ResetEvent(hEvent))
            {
                Int32 err = Marshal.GetLastWin32Error();
                throw new Win32Exception(err);
            }
        }

        internal static void DeviceIoControl(
            IntPtr hDevice,
            UInt32 dwIoControlCode,
            IntPtr lpInBuffer,
            UInt32 nInBufferSize,
            IntPtr lpOutBuffer,
            UInt32 nOutBufferSize,
            ref UInt32 lpBytesReturned,
            ref Waymex.Interop.NativeMethods.OVERLAPPED lpOverlapped)
        {
            if (!Waymex.Interop.NativeMethods.DeviceIoControl(hDevice,
                dwIoControlCode,
                lpInBuffer,
                nInBufferSize,
                lpOutBuffer,
                nOutBufferSize,
                ref lpBytesReturned,
                ref lpOverlapped))
            {
                Int32 err = Marshal.GetLastWin32Error();
                throw new Win32Exception(err);
            }
        }

        internal static void GetOverlappedResult(
            IntPtr hFile,
            Waymex.Interop.NativeMethods.OVERLAPPED lpOverlapped,
            ref UInt32 lpNumberOfBytesTransferred,
            [MarshalAs(UnmanagedType.Bool)] bool bWait)
        {
            if (!Waymex.Interop.NativeMethods.GetOverlappedResult(
                hFile,
                ref lpOverlapped,
                ref lpNumberOfBytesTransferred,
                bWait))
            {
                Int32 err = Marshal.GetLastWin32Error();
                throw new Win32Exception(err);
            }
        }


    }
}
//using System;
//using System.Diagnostics;
//using System.ComponentModel;
//using System.Collections.Generic;
//using System.Text;
//using System.Threading;
//using System.Runtime.InteropServices;
//using System.IO;
//using System.Xml.Serialization;
//using Waymex.Diagnostics;

//namespace Waymex.Interop
//{
//    /// <summary>
//    /// This class contains managed versions of the native methods exposed in Waymex.Interop.NativeMethods.
//    /// It includes helper functions error handling and marshalling specifics.
//    /// TODO: Enhance all these methods to handle overlapped results and accept standard CLR Types.
//    /// </summary>
//    internal sealed class ManagedMethods
//    {
//        //private constructor
//        private ManagedMethods() { }

//        internal static void CancelIo(IntPtr hFile)
//        {
//            if (!Waymex.Interop.NativeMethods.CancelIo(hFile))
//            {
//                Int32 err = Marshal.GetLastWin32Error();
//                throw new Win32Exception(err);
//            }
//        }
//        /// <summary>
//        /// 
//        /// </summary>
//        /// <returns></returns>
//        internal static byte[] ReadDeviceIoControlOverlapped(
//           IntPtr hDevice,
//           uint numberOfBytesToRead,
//           IntPtr overlappedEvent,
//           UInt32 dwIoControlCode,
//           int timeoutSeconds)
//        {
//            IntPtr lpOutBuffer = Marshal.AllocHGlobal((int)numberOfBytesToRead);
//            return ReadDeviceIoControlOverlapped(hDevice, lpOutBuffer, numberOfBytesToRead, overlappedEvent, dwIoControlCode, timeoutSeconds);

//        }
//       internal static byte[] ReadDeviceIoControlOverlapped(
//           IntPtr hDevice,
//           IntPtr lpOutBuffer,
//           uint numberOfBytesToRead,
//           IntPtr overlappedEvent,
//           UInt32 dwIoControlCode,
//           int timeoutSeconds)
//        {
//            //declarations
//            bool success = false;
//            bool complete = false;
//            byte[] dataReturned = new byte[numberOfBytesToRead];
//            byte[] data = null;
//            double timer = 0;
//            uint lpBytesReturned = 0;
//            int err = 0;
//            //IntPtr lpOutBuffer = IntPtr.Zero;

//            //uint lpNumberOfBytesTransferred = 0;
//            NativeMethods.OVERLAPPED lpOverlapped = new NativeMethods.OVERLAPPED();
//            //NativeMethods.DEVICEIODATA lpOutBuffer = new NativeMethods.DEVICEIODATA();

//            lpOverlapped.hEvent = overlappedEvent;

//            try
//            {

//                success = NativeMethods.DeviceIoControl(hDevice,
//                    dwIoControlCode,
//                    IntPtr.Zero,
//                    0,
//                    lpOutBuffer,
//                    numberOfBytesToRead,
//                    ref lpBytesReturned,
//                    ref lpOverlapped);

//                if (!success)
//                    err = Marshal.GetLastWin32Error();
//                else
//                    err = NativeMethods.NO_ERROR;

//                TraceLog.WriteMessage("DeviceIoControl returned " + lpBytesReturned.ToString() + " bytes. The Last Win32 error was " + err.ToString());

//                if (!success)
//                {
//                    switch (err)
//                    {
//                        case NativeMethods.ERROR_HANDLE_EOF:
//                            {
//                                // we have read all there is to read
//                                success = true;
//                                break;
//                            }

//                        case NativeMethods.ERROR_IO_PENDING:
//                            {

//                                timer = Timer();

//                                while (!complete)
//                                {
//                                    //required for .net2 on XP
//                                    System.Windows.Forms.Application.DoEvents();

//                                    complete = NativeMethods.GetOverlappedResult(hDevice, ref lpOverlapped, ref lpBytesReturned, false);
                                    
//                                    if (!complete)
//                                        err = Marshal.GetLastWin32Error();
//                                    else
//                                        err = NativeMethods.NO_ERROR;

//                                    TraceLog.WriteMessage("GetOverlappedResult returned " + lpBytesReturned.ToString() + " bytes. The Last Win32 error was " + err.ToString());

//                                    if (complete)
//                                    {
//                                        Marshal.Copy(lpOutBuffer, dataReturned, 0, dataReturned.Length);
//                                        success = true;
//                                        break;
//                                    }
//                                    else
//                                    {
//                                        switch (err)
//                                        {
//                                            case NativeMethods.ERROR_HANDLE_EOF:
//                                                {
//                                                    complete = true;
//                                                    success = true;
//                                                    break;
//                                                }

//                                            default:
//                                                {
//                                                    success = false;
//                                                    break;
//                                                }
//                                        }
//                                    }


//                                    //see if we have timed out
//                                    if (Timer() > timer + timeoutSeconds)
//                                    {
//                                        lpBytesReturned = 0;
//                                        break;
//                                    }
//                                }
//                                break;
//                            }

//                        default:
//                            {
//                                success = false;
//                                break;
//                            }
//                    }
//                }
//                else
//                {
//                    //was successful at first attempt
//                    Marshal.Copy(lpOutBuffer, dataReturned, 0, dataReturned.Length);
//                }

//                //tidy up data
//                if (success && lpBytesReturned > 0)
//                {
//                    //create an array the correct size for this packet
//                    data = new byte[lpBytesReturned];
//                    Array.Copy(dataReturned, 0, data, 0, lpBytesReturned);
//                }
//            }
//            catch (Exception e)
//            {
//                throw (e);
//            }
//            finally
//            {
//                //free up memory
//                //Marshal.FreeHGlobal(lpOutBuffer);
//                //NativeMethods.ResetEvent(overlappedEvent);
//            }

//            return data;
//        }
//        internal static bool WriteFileOverlapped(IntPtr hFile, IntPtr overlappedEvent, byte[] buffer, int timeoutSeconds)
//        {
//            bool success = false;
//            uint lpNumberOfBytesWritten = 0;
//            uint nNumberOfBytesToWrite = 0;
//            NativeMethods.OVERLAPPED lpOverlapped = new NativeMethods.OVERLAPPED();
//            int intError = 0;
//            double dblTimer = 0;
//            //IntPtr ptrUWO = IntPtr.Zero;

//            nNumberOfBytesToWrite = (uint)buffer.Length;
//            lpOverlapped.hEvent = overlappedEvent;

//            IntPtr lpBuffer = Marshal.AllocHGlobal(buffer.Length);
//            Marshal.Copy(buffer, 0, lpBuffer, buffer.Length);

//            success = NativeMethods.WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, ref lpNumberOfBytesWritten, ref lpOverlapped);

//            //need to determine if the overlapped write has completed
//            dblTimer = Timer();
//            while (nNumberOfBytesToWrite > lpNumberOfBytesWritten)
//            {
//                //required for XP systems
//                System.Windows.Forms.Application.DoEvents();

//                success = NativeMethods.GetOverlappedResult(hFile, ref lpOverlapped, ref lpNumberOfBytesWritten, false);

//                //see if we have timed out
//                if (Timer() > dblTimer + timeoutSeconds)
//                {
//                    break;
//                }
//            }

//            NativeMethods.ResetEvent(overlappedEvent);

//            if (success)
//            {
//                return true;
//            }

//            else
//            {

//                intError = Marshal.GetLastWin32Error();
//                return false;

//            }
//        }
//        /// <summary>
//        /// Method that performs a full overlapped read until the number of bytes
//        /// specified is read or until the timeout period expires.
//        /// </summary>
//        /// <returns></returns>
//        internal static byte[] ReadFileOverlapped(IntPtr hFile,
//            uint numberOfBytesToRead,
//            IntPtr overlappedEvent,
//            int timeoutSeconds)
//        {
//            //marshal a pointer to the data buffer
//            IntPtr lpBuffer = Marshal.AllocHGlobal((int)numberOfBytesToRead);
//            return ReadFileOverlapped(hFile, lpBuffer, numberOfBytesToRead, overlappedEvent, timeoutSeconds);

//        }
//        /// Method that performs a full overlapped read until the number of bytes
//        /// specified is read or until the timeout period expires. This overload accepts an
//        /// externally created buffer allowing for greater control.
//        internal static byte[] ReadFileOverlapped(IntPtr hFile,
//            IntPtr lpBuffer,
//            uint numberOfBytesToRead,
//            IntPtr overlappedEvent,
//            int timeoutSeconds)
//        {

//            //declarations
//            bool success = false;
//            bool complete = false;
//            Double timer = 0;
//            Int32 err = 0;
//            byte[] data = null;
//            uint lpNumberOfBytesRead = 0;
//            byte[] dataReturned = new byte[numberOfBytesToRead];
//            NativeMethods.OVERLAPPED lpOverlapped = new NativeMethods.OVERLAPPED();
//            uint lpNumberOfBytesTransferred = 0;

//            /*
//             * ReadFile returns false with error ERROR_IO_PENDING when more data is avalable
//             * Event set to signalled state whenread completes.
//             * If Readfile gets to end of file then it returns false and error is ERROR_HANDLE_EOF.
//             * If subsequent GetOverlapped Result gets to end of file then this also returns false
//             * and error is ERROR_HANDLE_EOF.
//             * 
//             */

//            lpOverlapped.hEvent = overlappedEvent;

//            try
//            {
//                //marshal a pointer to the data buffer
//                //lpBuffer = Marshal.AllocHGlobal((int)numberOfBytesToRead);

//                //call native function
//                success = Waymex.Interop.NativeMethods.ReadFile(hFile,
//                    lpBuffer,
//                    numberOfBytesToRead,
//                    ref lpNumberOfBytesRead,
//                    ref lpOverlapped);

//                if (!success)
//                    err = Marshal.GetLastWin32Error();
//                else
//                    err = NativeMethods.NO_ERROR;

//                if (!success)
//                {
//                    switch (err)
//                    {
//                        case NativeMethods.ERROR_HANDLE_EOF:
//                            {
//                                // we have read all there is to read
//                                success = true;
//                                break;
//                            }

//                        case NativeMethods.ERROR_IO_PENDING:
//                            {
//                                //asynchronous i/o is still in progress
//                                timer = Timer();

//                                //loop until it is complete
//                                while (!complete)
//                                {
//                                    //required for .net2 on XP
//                                    System.Windows.Forms.Application.DoEvents();

//                                    //get the overlapped result
//                                    complete = NativeMethods.GetOverlappedResult(hFile, ref lpOverlapped, ref lpNumberOfBytesTransferred, false);
//                                    if (!complete)
//                                        err = Marshal.GetLastWin32Error();
//                                    else
//                                        err = NativeMethods.NO_ERROR;

//                                    if (complete)
//                                    {
//                                        Marshal.Copy(lpBuffer, dataReturned, 0, dataReturned.Length);
//                                        success = true;
//                                        break;
//                                    }
//                                    else
//                                    {
//                                        switch (err)
//                                        {
//                                            case NativeMethods.ERROR_HANDLE_EOF:
//                                                {
//                                                    complete = true;
//                                                    success = true;
//                                                    break;
//                                                }
//                                            default:
//                                                {
//                                                    success = false;
//                                                    break;
//                                                }
//                                        }
//                                    }

//                                    //see if we have timed out
//                                    if (Timer() > (timer + timeoutSeconds))
//                                    {
//                                        lpNumberOfBytesTransferred = 0;
//                                        success = false;
//                                        break;
//                                    }

//                                }
//                                break;
//                            }
//                        default:
//                            {
//                                break;
//                            }
//                    }
//                }
//                else
//                {
//                    //was successful at first attempt
//                    Marshal.Copy(lpBuffer, dataReturned, 0, dataReturned.Length);
//                }

//                //tidy up data
//                if (success && lpNumberOfBytesTransferred > 0)
//                {

//                    //make an array exactly the correct length
//                    data = new byte[lpNumberOfBytesTransferred];

//                    //copy the returned data in to the new array
//                    Array.Copy(dataReturned, data, lpNumberOfBytesTransferred);
//                }
//            }
//            catch (Exception e)
//            {
//                throw (e);
//            }
//            finally
//            {
//                //free up memory
//                //Marshal.FreeHGlobal(lpBuffer);
//                //NativeMethods.ResetEvent(overlappedEvent);
//            }

//            return data;
//        }
//        private static double Timer()
//        {
//            DateTime dtTimer;

//            dtTimer = DateTime.Now;

//            //Debug.Write("Timer() ");     
//            //Debug.WriteLine(dtTimer.Ticks % 711573504 / 1e+007);
//            return (double)dtTimer.Ticks % 711573504 / 1e+007;
//        }
//        internal static void ReadFile(IntPtr hFile,
//            IntPtr lpBuffer,
//            UInt32 nNumberOfBytesToRead,
//            ref UInt32 lpNumberOfBytesRead,
//            ref Waymex.Interop.NativeMethods.OVERLAPPED lpOverlapped)
//        {
//            if (!Waymex.Interop.NativeMethods.ReadFile(hFile,
//                lpBuffer,
//                nNumberOfBytesToRead,
//                ref lpNumberOfBytesRead,
//                ref lpOverlapped))
//            {
//                Int32 err = Marshal.GetLastWin32Error();
//                throw new Win32Exception(err);
//            }
//        }
//        internal static void WriteFile(IntPtr hFile,
//            IntPtr lpBuffer,
//            UInt32 nNumberOfBytesToWrite,
//            ref UInt32 lpNumberOfBytesWritten,
//            ref Waymex.Interop.NativeMethods.OVERLAPPED lpOverlapped)
//        {
//            if (!Waymex.Interop.NativeMethods.WriteFile(hFile,
//                lpBuffer,
//                nNumberOfBytesToWrite,
//                ref lpNumberOfBytesWritten,
//                ref lpOverlapped))
//            {
//                Int32 err = Marshal.GetLastWin32Error();
//                throw new Win32Exception(err);
//            }
//        }
//        internal static IntPtr CreateEvent(
//            IntPtr lpEventAttributes,
//            int bManualReset,
//            int bInitialState,
//            string lpName)
//        {
//            IntPtr handle = Waymex.Interop.NativeMethods.CreateEvent(lpEventAttributes,
//                bManualReset,
//                bInitialState,
//                lpName);
//            if (handle == IntPtr.Zero)
//            {
//                Int32 err = Marshal.GetLastWin32Error();
//                throw new Win32Exception(err);
//            }

//            return handle;
//        }

//        internal static IntPtr CreateFile(
//            String lpFileName,
//            UInt32 dwDesiredAccess,
//            UInt32 dwShareMode,
//            IntPtr lpSecurityAttributes,
//            UInt32 dwCreationDisposition,
//            UInt32 dwFlagsAndAttributes,
//            IntPtr hTemplateFile)
//        {
//            IntPtr handle = Waymex.Interop.NativeMethods.CreateFile(lpFileName,
//                dwDesiredAccess,
//                dwShareMode,
//                lpSecurityAttributes,
//                dwCreationDisposition,
//                dwFlagsAndAttributes,
//                hTemplateFile
//                );

//            if (handle == IntPtr.Zero)
//            {
//                Int32 err = Marshal.GetLastWin32Error();
//                throw new Win32Exception(err);
//            }

//            return handle;
//        }

//        internal static void SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet)
//        {
//            if (!Waymex.Interop.NativeMethods.SetupDiDestroyDeviceInfoList(DeviceInfoSet))
//            {
//                Int32 err = Marshal.GetLastWin32Error();
//                throw new Win32Exception(err);
//            }
//        }

//        internal static void SetupDiGetDeviceInterfaceDetail(
//            IntPtr DeviceInfoSet,
//            ref Waymex.Interop.NativeMethods.DEVICE_INTERFACE_DATA DeviceInterfaceData,
//            //ref Waymex.Interop.NativeMethods.DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData,
//            IntPtr DeviceInterfaceDetailData,
//            int DeviceInterfaceDetailDataSize,
//            ref int RequiredSize,
//            IntPtr DeviceInfoData)
//        {
//            if (!Waymex.Interop.NativeMethods.SetupDiGetDeviceInterfaceDetail(DeviceInfoSet,
//                ref DeviceInterfaceData,
//                DeviceInterfaceDetailData,
//                DeviceInterfaceDetailDataSize,
//                ref RequiredSize,
//                DeviceInfoData))
//            {
//                Int32 err = Marshal.GetLastWin32Error();
//                throw new Win32Exception(err);
//            }
//        }

//        internal static IntPtr SetupDiGetClassDevs(
//            ref Guid ClassGuid,
//            string Enumerator,
//            IntPtr hwndParent,
//            uint Flags)
//        {
//            IntPtr handle = Waymex.Interop.NativeMethods.SetupDiGetClassDevs(ref ClassGuid,
//                Enumerator,
//                hwndParent,
//                Flags);
//            if (handle == IntPtr.Zero)
//            {
//                Int32 err = Marshal.GetLastWin32Error();
//                throw new Win32Exception(err);
//            }

//            return handle;

//        }

//        internal static void CloseHandle(IntPtr hObject)
//        {
//            if (!Waymex.Interop.NativeMethods.CloseHandle(hObject))
//            {
//                Int32 err = Marshal.GetLastWin32Error();
//                throw new Win32Exception(err);
//            }
//        }

//        internal static void SetupDiEnumDeviceInterfaces(
//            IntPtr DeviceInfoSet,
//            IntPtr DeviceInfoData,
//            ref Guid InterfaceClassGuid,
//            int MemberIndex,
//            ref Waymex.Interop.NativeMethods.DEVICE_INTERFACE_DATA DeviceInterfaceData)
//        {
//            if (!Waymex.Interop.NativeMethods.SetupDiEnumDeviceInterfaces(DeviceInfoSet,
//                DeviceInfoData,
//                ref InterfaceClassGuid,
//                MemberIndex,
//                ref DeviceInterfaceData))
//            {
//                Int32 err = Marshal.GetLastWin32Error();
//                throw new Win32Exception(err);
//            }
//        }

//        internal static void ResetEvent(
//            IntPtr hEvent)
//        {
//            if (!Waymex.Interop.NativeMethods.ResetEvent(hEvent))
//            {
//                Int32 err = Marshal.GetLastWin32Error();
//                throw new Win32Exception(err);
//            }
//        }

//        internal static void DeviceIoControl(
//            IntPtr hDevice,
//            UInt32 dwIoControlCode,
//            IntPtr lpInBuffer,
//            UInt32 nInBufferSize,
//            IntPtr lpOutBuffer,
//            UInt32 nOutBufferSize,
//            ref UInt32 lpBytesReturned,
//            ref Waymex.Interop.NativeMethods.OVERLAPPED lpOverlapped)
//        {
//            if (!Waymex.Interop.NativeMethods.DeviceIoControl(hDevice,
//                dwIoControlCode,
//                lpInBuffer,
//                nInBufferSize,
//                lpOutBuffer,
//                nOutBufferSize,
//                ref lpBytesReturned,
//                ref lpOverlapped))
//            {
//                Int32 err = Marshal.GetLastWin32Error();
//                throw new Win32Exception(err);
//            }
//        }

//        internal static void GetOverlappedResult(
//            IntPtr hFile,
//            Waymex.Interop.NativeMethods.OVERLAPPED lpOverlapped,
//            ref UInt32 lpNumberOfBytesTransferred,
//            [MarshalAs(UnmanagedType.Bool)] bool bWait)
//        {
//            if (!Waymex.Interop.NativeMethods.GetOverlappedResult(
//                hFile,
//                ref lpOverlapped,
//                ref lpNumberOfBytesTransferred,
//                bWait))
//            {
//                Int32 err = Marshal.GetLastWin32Error();
//                throw new Win32Exception(err);
//            }
//        }


//    }
//}
